import type { App, Directive } from "vue"

interface ResizerOptions {
    targetSelector: string
    observerProperty: 'width' | 'height' | 'all'
}

// 在延时加载的 iframe 中定时器循环查找对应的目标节点，默认每 200 毫秒查找一次，查 100 次
function delayLoadIframeDom (el: HTMLIFrameElement, targetSelector: string, maxCount = 100, delay = 200): Promise<HTMLElement | undefined> {
    return new Promise((resolve, reject) => {
        let count = 0;
        let targetEl = (el as HTMLIFrameElement).contentDocument?.querySelector(targetSelector)
        function myTimer() {
            targetEl = (el as HTMLIFrameElement).contentDocument?.querySelector(targetSelector)
            if (targetEl) {
                resolve(targetEl as HTMLElement)
            } else {
                count++;
                if (count < maxCount) {
                    setTimeout(myTimer, delay);
                } else {
                    reject('Element not exist: ' + targetSelector)
                }
            }
        }
        myTimer()
    })
}

function observerNode (el: HTMLElement, callback: (...arg: any[]) => void): MutationObserver {
    // 观察器的配置（需要观察什么变动）
    const config = { attributes: true, childList: true, characterData: true, subtree: true }
    // 创建一个观察器实例并传入回调函数
    const observer = new MutationObserver(callback);
    // 以上述配置开始观察目标节点
    observer.observe(el, config);
    return observer
}

// 设置元素的宽高
function setHeightWidth (el: HTMLElement, targetEl: HTMLElement, observerProperty: 'width' | 'height' | 'all') {
    // 计算 targetEl 宽高
    const height = targetEl.offsetHeight
    const width = targetEl.offsetWidth
    if(observerProperty === 'height') {
        el.style.height = height + 'px'
    } else if(observerProperty === 'width') {
        el.style.width = width + 'px'
    } else if(observerProperty === 'all') {
        el.style.height = height + 'px'
        el.style.width = width + 'px'
    }
}

export const resizer: Directive = {
    mounted (el: HTMLElement, binding: { value: ResizerOptions }) {
        const { value } = binding
        el.style.display = 'block'
        let targetSelector = '#resizer'
        const domType: 'iframe' | 'element' = el.tagName === 'IFRAME' ? 'iframe' : 'element'
        let observerProperty: 'width' | 'height' | 'all' = 'height'
        if (value) {
            if(value.targetSelector) {
                targetSelector = value.targetSelector
            }
            if(value.observerProperty) {
                observerProperty = value.observerProperty
            }
        }

        // 查找监听的元素
        let targetEl: HTMLElement
        if(domType === 'element') {
            targetEl = document.querySelector(targetSelector) as HTMLElement
            setHeightWidth(el, targetEl, observerProperty)
            observerNode(targetEl, callback)
        } else if(domType === 'iframe') {
            delayLoadIframeDom(el as HTMLIFrameElement, targetSelector).then(res => {
                if(res){
                    targetEl = res
                    setHeightWidth(el, targetEl, observerProperty)
                    observerNode(targetEl, callback)
                }
            }).catch(err => {
                console.error(err)
            })
        }

        // 当观察到变动时执行的回调函数
        function callback() {
            setHeightWidth(el, targetEl, observerProperty)
        }
    }
}
    

  export default {
    install(app: App) {
        app.directive('resizer', resizer)
    }
  }